package com.ctg.itrdc.imageconsole.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.ctg.itrdc.imageconsole.common.constants.K8sConstant;
import com.ctg.itrdc.imageconsole.common.util.TimeUtils;
import com.ctg.itrdc.imageconsole.data.dao.IClusterConfigDao;
import com.ctg.itrdc.imageconsole.data.dao.IK8sNamespaceDao;
import com.ctg.itrdc.imageconsole.data.dto.K8sNamespaceDTO;
import com.ctg.itrdc.imageconsole.data.entity.ClusterConfig;
import com.ctg.itrdc.imageconsole.data.entity.K8sNamespace;
import com.ctg.itrdc.imageconsole.service.IK8sNamespaceService;
import com.ctg.itrdc.imageconsole.util.KubeUtils;
import com.ctg.itrdc.pasp.security.utils.WebUtils;
import com.ctg.itrdc.paspsdk.common.entity.PageInfo;
import com.ctg.itrdc.paspsdk.common.utils.json.JSONUtils;

import io.fabric8.kubernetes.api.model.LimitRange;
import io.fabric8.kubernetes.api.model.LimitRangeItem;
import io.fabric8.kubernetes.api.model.LimitRangeSpec;
import io.fabric8.kubernetes.api.model.Namespace;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.api.model.Quantity;
import io.fabric8.kubernetes.api.model.ResourceQuota;
import io.fabric8.kubernetes.api.model.ResourceQuotaSpec;

@Component("k8sNamespaceService")
public class K8sNamespaceServiceImpl implements IK8sNamespaceService {

	private static final Logger logger = LoggerFactory.getLogger(K8sNamespaceServiceImpl.class);

	@Resource
	private IK8sNamespaceDao k8sNamespaceDao;
	@Resource
	private IClusterConfigDao clusterConfigDao;

	@Override
	public PageInfo<K8sNamespaceDTO> queryNamespaceList(K8sNamespaceDTO namespaceDTO, Integer pageNum,
			Integer pageSize) {
		PageInfo<K8sNamespaceDTO> pageInfo = k8sNamespaceDao.jdbcFindPageInfo(namespaceDTO, pageNum,
				pageSize);
		
		for(K8sNamespaceDTO dto : pageInfo.getList()){
			if (null == dto.getNamespaceName()) {
				// 由于应用发布功能那里的原因，在spring-mvc.xml中配置JsonInclude为NON_NULL，所以加了下面这行代码的操作
				dto.setNamespaceName("");
			}
			if (K8sConstant.NP_CREATE_SUCCESS.equals(dto.getStatus())) {
				queryQuota(dto);
			}
		}

		return pageInfo;
	}

	private K8sNamespaceDTO queryQuota(K8sNamespaceDTO namespaceDTO){
		ClusterConfig clusterConfig = clusterConfigDao.queryByClusterCode(namespaceDTO.getClusterCode());
		
		String namespaceJson = KubeUtils.queryNamespace(clusterConfig.getApiServerUrl(), namespaceDTO.getNamespaceCode());
		if (null == namespaceJson) {
			namespaceDTO.setStatus(K8sConstant.NP_EXCEPTION);
			return namespaceDTO;
		}
		Namespace namespace = JSONUtils.jsonToObject(namespaceJson, Namespace.class);
		
		String quotasJson = KubeUtils.queryResouceQuotas(clusterConfig.getApiServerUrl(), namespace.getMetadata().getName());
		Map<String, Object> map = JSONUtils.jsonToMap(quotasJson);
		List<Map<String, Object>> items = (List<Map<String, Object>>) map.get("items");
		
		// TODO 目前items集合的大小只会为1
		for(Map<String, Object> item:items){
			Map<String, Object> statusMap = (Map<String, Object>) item.get("status");
			Map<String, Object> usedMap = (Map<String, Object>) statusMap.get("used");
			String usedCpu = (String) usedMap.get("limits.cpu");
			if (!usedCpu.contains("m")) {
				usedCpu = Integer.valueOf(usedCpu) * 1000 +"m";
			}
			String usedMemory = (String) usedMap.get("limits.memory");
			if (usedMemory.contains("G")) {
				usedMemory = Integer.valueOf(usedMemory.substring(0,usedMemory.indexOf("G"))) * 1000 +"M";
			}
			String usedPods = (String) usedMap.get("pods");
			String usedRcs = (String) usedMap.get("replicationcontrollers");
			namespaceDTO.setUsedCpu(usedCpu);
			namespaceDTO.setUsedMemory(usedMemory);
			namespaceDTO.setUsedPods(usedPods);
			namespaceDTO.setUsedRcs(usedRcs);
		}
		return namespaceDTO;
	}

	@Override
	public boolean checkIsExist(String clusterCode, String namespaceCode) {
		Long createUserId = WebUtils.getCtgUser().getSysUserId();

		K8sNamespace namespace = new K8sNamespace();
		namespace.setClusterCode(clusterCode);
		namespace.setNamespaceCode(namespaceCode);
		namespace.setCreateUserId(createUserId);
		
		List<K8sNamespace> namespaces = k8sNamespaceDao.selectByExample(namespace);
		if (namespaces != null && namespaces.size()>0) {
			return true;
		}
		return false;
	}

	@Override
	public void createNamepace(K8sNamespace k8sNamespace) {
		// 保存数据到数据库
		k8sNamespace.setStatus(K8sConstant.NP_CREATING);
		k8sNamespace.setCreateUserId(WebUtils.getCtgUser().getSysUserId());
		k8sNamespace.setCreateTime(TimeUtils.getNowDateStr());
		k8sNamespace.setLastUpdateUserId(WebUtils.getCtgUser().getSysUserId());
		k8sNamespace.setLastUpdateTime(TimeUtils.getNowDateStr());
		long id = k8sNamespaceDao.insert(k8sNamespace);
		K8sNamespace namespaceByInsert = new K8sNamespace();
		namespaceByInsert.setId(id);
		namespaceByInsert = k8sNamespaceDao.selectByPrimaryKey(namespaceByInsert);
		try {
			String apiServerUrl = clusterConfigDao.selectApiServerUrlByClusterCode(k8sNamespace.getClusterCode());
			
			// 创建namespace
			KubeUtils.createOrUpdateNamespace(apiServerUrl, null, k8sNamespace.getNamespaceYaml());
			Thread.sleep(100);
			// 根据namespace创建quota
			KubeUtils.createOrUpdateResourceQuota(apiServerUrl, k8sNamespace.getNamespaceCode(), null, k8sNamespace.getQuotaYaml());
			// 根据namespace创建limits
			KubeUtils.createOrUpdateLimitRange(apiServerUrl, k8sNamespace.getNamespaceCode(), null, k8sNamespace.getLimitsYaml());
			
			namespaceByInsert.setStatus(K8sConstant.NP_CREATE_SUCCESS);
		} catch (Exception e) {
			logger.error("catch exception when createNamepace !", e);
			namespaceByInsert.setStatus(K8sConstant.NP_CREATE_FAIL);
		} finally {
			k8sNamespaceDao.updateByPrimaryKey(namespaceByInsert);
		}
	}
	
	
	@Override
	public void updateNamepace(K8sNamespace k8sNamespace) {
		// 保存数据到数据库
		k8sNamespace.setStatus(K8sConstant.NP_CREATING);
		k8sNamespace.setCreateUserId(WebUtils.getCtgUser().getSysUserId());
		k8sNamespace.setCreateTime(TimeUtils.getNowDateStr());
		k8sNamespace.setLastUpdateUserId(WebUtils.getCtgUser().getSysUserId());
		k8sNamespace.setLastUpdateTime(TimeUtils.getNowDateStr());
		k8sNamespaceDao.updateByPrimaryKey(k8sNamespace);
		try {
			String quotaName = "quota-" + k8sNamespace.getNamespaceCode();
			String limitRangeName = "limits-" + k8sNamespace.getNamespaceCode();
			
			String apiServerUrl = clusterConfigDao.selectApiServerUrlByClusterCode(k8sNamespace.getClusterCode());
			
			KubeUtils.createOrUpdateNamespace(apiServerUrl, k8sNamespace.getNamespaceCode(), k8sNamespace.getNamespaceYaml());
			Thread.sleep(100);

			KubeUtils.createOrUpdateResourceQuota(apiServerUrl, k8sNamespace.getNamespaceCode(), quotaName, k8sNamespace.getQuotaYaml());
			KubeUtils.createOrUpdateLimitRange(apiServerUrl, k8sNamespace.getNamespaceCode(), limitRangeName, k8sNamespace.getLimitsYaml());
			
			k8sNamespace.setStatus(K8sConstant.NP_CREATE_SUCCESS);
		} catch (Exception e) {
			logger.error("catch exception when createNamepace !", e);
			k8sNamespace.setStatus(K8sConstant.NP_CREATE_FAIL);
		} finally {
			k8sNamespaceDao.updateByPrimaryKey(k8sNamespace);
		}
	}

	@Override
	public List<Object> combineJson(K8sNamespace k8sNamespace) {
//		Map<String, Object> map = new HashMap<>();
//		map.put("namespaceJson", combineNamespace(k8sNamespace));
//		map.put("quotaJson", combineQuota(k8sNamespace));
//		map.put("limitsJson", combineLimitRange(k8sNamespace));
		List<Object> list = new ArrayList<>();
		list.add(combineNamespace(k8sNamespace));
		list.add(combineQuota(k8sNamespace));
		list.add(combineLimitRange(k8sNamespace));
		
		return list;
	}
	
	private Namespace combineNamespace(K8sNamespace k8sNamespace){
		Namespace namespace = new Namespace();
		namespace.setKind("Namespace");
		namespace.setApiVersion("v1");
		namespace.setMetadata(new ObjectMeta());
		namespace.getMetadata().setName(k8sNamespace.getNamespaceCode());
		namespace.getMetadata().setFinalizers(null);
		namespace.getMetadata().setOwnerReferences(null);
		
		return namespace;
	}

	private ResourceQuota combineQuota(K8sNamespace k8sNamespace) {
		ResourceQuota quota = new ResourceQuota();
		quota.setKind("ResourceQuota");
		quota.setApiVersion("v1");
		quota.setMetadata(new ObjectMeta());
		quota.getMetadata().setName("quota-" + k8sNamespace.getNamespaceCode());
		quota.getMetadata().setFinalizers(null);
		quota.getMetadata().setOwnerReferences(null);
		quota.setSpec(new ResourceQuotaSpec());
		quota.getSpec().setScopes(null);
		quota.getSpec().setHard(new HashMap<String, Quantity>());
		Quantity cpuQuotaQ = new Quantity(k8sNamespace.getCpuQuota().toString());
		Quantity memoryQuotaQ = new Quantity(k8sNamespace.getMemoryQuota() + "M");
		Quantity persistentvolumeclaimsQ = new Quantity("40");
		Quantity podQuotaQ = new Quantity(k8sNamespace.getPodQuota().toString());
//		Quantity rcQuotaQ = new Quantity(k8sNamespace.getRcQuota().toString());
		Quantity resourcequotasQ = new Quantity("1");
		Quantity secretsQ = new Quantity("40");
		Quantity servicesQ = new Quantity("20");
		quota.getSpec().getHard().put("limits.cpu", cpuQuotaQ);
		quota.getSpec().getHard().put("limits.memory", memoryQuotaQ);
		quota.getSpec().getHard().put("persistentvolumeclaims", persistentvolumeclaimsQ);
		quota.getSpec().getHard().put("pods", podQuotaQ);
//		quota.getSpec().getHard().put("replicationcontrollers", rcQuotaQ);
		quota.getSpec().getHard().put("resourcequotas", resourcequotasQ);
		quota.getSpec().getHard().put("secrets", secretsQ);
		quota.getSpec().getHard().put("services", servicesQ);
		
		return quota;
	}
	
	private LimitRange combineLimitRange(K8sNamespace k8sNamespace) {
		LimitRange limitRange = new LimitRange();
		limitRange.setKind("LimitRange");
		limitRange.setApiVersion("v1");
		limitRange.setMetadata(new ObjectMeta());
		limitRange.getMetadata().setFinalizers(null);
		limitRange.getMetadata().setOwnerReferences(null);
		limitRange.getMetadata().setName("limits-" + k8sNamespace.getNamespaceCode());
		limitRange.setSpec(new LimitRangeSpec());
		limitRange.getSpec().setLimits(new ArrayList<LimitRangeItem>());
		LimitRangeItem rangeItem = new LimitRangeItem();
		rangeItem.setDefault(new HashMap<String, Quantity>());
		
		Quantity cpuQ = new Quantity("100");
		Quantity memoryQ = new Quantity("512M");
		rangeItem.getDefault().put("cpu", cpuQ);
		rangeItem.getDefault().put("memory", memoryQ);
		rangeItem.setType("Container");
		
		limitRange.getSpec().getLimits().add(rangeItem);
		
		return limitRange;
	}

	@Override
	public void deleteNamepace(K8sNamespace namespace) {
		// 删除数据库记录
		k8sNamespaceDao.deleteByPrimaryKey(namespace);
		// 删除命名空间
		String apiServerUrl = clusterConfigDao.selectApiServerUrlByClusterCode(namespace.getClusterCode());
		KubeUtils.deleteNamespace(apiServerUrl, namespace.getNamespaceCode());
		
		// 删除命名空间下面的所有应用
	}

	@Override
	public K8sNamespace queryNamespaceById(Long id) {
		K8sNamespace k8sNamespace = new K8sNamespace();
		k8sNamespace.setId(id);
		
		return k8sNamespaceDao.selectByPrimaryKey(k8sNamespace);
	}
	
}
